package com.wcq.studentbackend.controller;

import com.wcq.studentbackend.dto.LoginRequestDTO;
import com.wcq.studentbackend.dto.LoginResponseDTO;
import com.wcq.studentbackend.entity.AdminUser;
import com.wcq.studentbackend.entity.Student;
import com.wcq.studentbackend.mapper.AdminUserMapper;
import com.wcq.studentbackend.mapper.StudentMapper;
import com.wcq.studentbackend.util.JwtUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.stream.Collectors;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.validation.Valid;

@Slf4j
@RestController
@RequestMapping("/api/auth")
@Api(tags = "用户认证相关接口")
public class AuthController {

    private final AuthenticationManager authenticationManager;
    private final AdminUserMapper adminUserMapper;
    private final StudentMapper studentMapper;
    private final JwtUtil jwtUtil;
    
    // 用于记录登录失败次数
    private final Map<String, Integer> loginAttempts = new ConcurrentHashMap<>();
    private static final int MAX_LOGIN_ATTEMPTS = 5;
    private static final long LOCK_TIME_DURATION = 30 * 60 * 1000; // 30分钟
    private final Map<String, Long> lockoutTime = new ConcurrentHashMap<>();

    @Autowired
    public AuthController(AuthenticationManager authenticationManager,
                          AdminUserMapper adminUserMapper,
                          StudentMapper studentMapper,
                          JwtUtil jwtUtil) {
        this.authenticationManager = authenticationManager;
        this.adminUserMapper = adminUserMapper;
        this.studentMapper = studentMapper;
        this.jwtUtil = jwtUtil;
    }

    @PostMapping("/login")
    @ApiOperation("用户登录")
    public ResponseEntity<?> loginUser(@Valid @RequestBody LoginRequestDTO loginRequest) {
        try {
            // 检查账户是否被锁定
            String username = loginRequest.getUsername();
            if (isAccountLocked(username)) {
                return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS)
                    .body("账户已被锁定，请稍后再试");
            }

            // 格式化用户名：role:identifier
            String formattedUsername = loginRequest.getRole() + ":" + loginRequest.getUsername();
            log.debug("尝试登录用户: {}, 密码: {}", formattedUsername, loginRequest.getPassword());
            
            // 创建认证令牌
            Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                    formattedUsername,
                    loginRequest.getPassword()
                )
            );

            // 认证成功，清除登录失败记录
            loginAttempts.remove(username);
            lockoutTime.remove(username);

            // 设置认证信息
            SecurityContextHolder.getContext().setAuthentication(authentication);
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            log.debug("认证成功，用户详情: {}", userDetails);

            // 生成JWT令牌
            String token = jwtUtil.generateToken(userDetails, loginRequest.getRole());

            // 获取用户显示名称
            String displayName = getDisplayName(loginRequest.getUsername(), loginRequest.getRole());

            // 构建响应
            LoginResponseDTO response = new LoginResponseDTO();
            response.setMessage("登录成功");
            response.setUsername(loginRequest.getUsername());
            response.setName(displayName);
            response.setRole(loginRequest.getRole());
            response.setAuthorities(userDetails.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toList()));
            response.setToken(token);

            log.debug("用户 {} 登录成功", formattedUsername);
            return ResponseEntity.ok(response);

        } catch (BadCredentialsException e) {
            // 处理登录失败
            handleFailedLogin(loginRequest.getUsername());
            int remainingAttempts = MAX_LOGIN_ATTEMPTS - loginAttempts.getOrDefault(loginRequest.getUsername(), 0);
            
            // 添加更详细的错误信息
            String errorMessage = "用户名或密码错误";
            if (remainingAttempts > 0) {
                errorMessage += "，剩余尝试次数：" + remainingAttempts;
            } else {
                errorMessage += "，账户已被锁定，请30分钟后再试";
            }
            
            log.warn("用户 {} 登录失败: {}", loginRequest.getUsername(), errorMessage);
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                .body(errorMessage);
        } catch (LockedException e) {
            log.warn("用户 {} 尝试登录时账户已被锁定", loginRequest.getUsername());
            return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS)
                .body("账户已被锁定，请稍后再试");
        } catch (Exception e) {
            log.error("登录过程中发生错误", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body("登录过程中发生错误，请稍后重试");
        }
    }

    private boolean isAccountLocked(String username) {
        Long lockTime = lockoutTime.get(username);
        if (lockTime != null && lockTime > System.currentTimeMillis()) {
            return true;
        }
        // 如果锁定时间已过，清除锁定记录
        if (lockTime != null) {
            lockoutTime.remove(username);
            loginAttempts.remove(username);
        }
        return false;
    }

    private void handleFailedLogin(String username) {
        int attempts = loginAttempts.getOrDefault(username, 0) + 1;
        loginAttempts.put(username, attempts);
        
        if (attempts >= MAX_LOGIN_ATTEMPTS) {
            long lockTime = System.currentTimeMillis() + LOCK_TIME_DURATION;
            lockoutTime.put(username, lockTime);
            log.warn("账户 {} 因多次登录失败已被锁定", username);
        }
    }

    private String getDisplayName(String username, String role) {
        try {
            if ("admin".equalsIgnoreCase(role)) {
                AdminUser admin = adminUserMapper.selectOne(
                    new QueryWrapper<AdminUser>().eq("username", username)
                );
                return admin != null ? admin.getName() : username;
            } else if ("student".equalsIgnoreCase(role)) {
                Student student = studentMapper.selectOne(
                    new QueryWrapper<Student>().eq("stu_no", username)
                );
                return student != null ? student.getName() : username;
            }
        } catch (Exception e) {
            log.error("获取用户显示名称时发生错误: {}", e.getMessage());
        }
        return username;
    }
} 